<template>
  <div
    class="chart-container"
    :style="{ width: width, height: height, background: background }"
  >
    <div ref="mainChart" class="main-chart"></div>
    <div ref="volumeChart" class="volume-chart"></div>
  </div>
</template>

<script setup>
import { ref, onMounted, onBeforeUnmount, defineProps, watch } from "vue";
import * as echarts from "echarts";
const props = defineProps({
  timeData: {
    type: Object,
    required: true,
  },
  width: {
    type: String,
    required: false,
    default: "1000px",
  },
  height: {
    type: String,
    required: false,
    default: "650px",
  },
  background: {
    type: String,
    required: false,
    default: "#fff",
  },
});
watch(
  () => props.stockData,
  (newVal) => {
    if (newVal.data && newVal.data.length > 0) {
      updateCharts();
    }
  }
);
const mainChart = ref(null);
const volumeChart = ref(null);
let mainInstance = null;
let volumeInstance = null;
let dataTimer = null;
let currentIndex = 0;

const convertTimeToMins = (timeStr) => {
  const hour = parseInt(timeStr.substr(0, 2));
  const minute = parseInt(timeStr.substr(2));
  const totalMinutes = hour * 60 + minute;

  if (totalMinutes >= 570 && totalMinutes <= 690) {
    return totalMinutes - 570;
  }
  if (totalMinutes >= 780 && totalMinutes <= 900) {
    return totalMinutes - 780 + 121;
  }
  return null;
};

const formatFullTime = (timeStr) => {
  return `${props.timeData.day} ${timeStr.slice(0, 2)}:${timeStr.slice(2)}`;
};

const tradingData = props.timeData.data
  .map((item) => {
    const converted = convertTimeToMins(item[0]);
    return converted !== null ? { ...item, convertedTime: converted } : null;
  })
  .filter(Boolean);

const processData = () => {
  const sliced = tradingData.slice(0, currentIndex + 1);
  const prices = sliced.map((item) => item[1]);
  const volumes = sliced.map((item) => item[3]);
  const avgPrice = sliced.length > 0 ? sliced[sliced.length - 1][2] : 0;
  const currentVolume =
    sliced.length > 0 ? (sliced[sliced.length - 1][3] / 10000).toFixed(1) : 0;
  return {
    prices: sliced.map((item) => [item.convertedTime, item[1]]),
    avgPrices: sliced.map((item) => [item.convertedTime, item[2]]),
    volumes: sliced.map((item) => ({
      time: item.convertedTime,
      value: item[3],
      price: item[1],
      avgPrice: item[2],
    })),
    minPrice: Math.min(...prices),
    maxPrice: Math.max(...prices),
    maxVolume: Math.max(...volumes),
    currentVolume,
    currentAvgPrice: avgPrice.toFixed(2),
  };
};

const getMainOption = (data) => {
  const preClose = props.timeData.pre_close;
  const valueMax = () => {
    if (
      Math.abs(data.maxPrice - preClose) > Math.abs(preClose - data.minPrice)
    ) {
      return data.maxPrice;
    } else {
      return (preClose + (preClose - data.minPrice)).toFixed(2);
    }
  };
  const valueMin = () => {
    if (
      Math.abs(data.maxPrice - preClose) > Math.abs(preClose - data.minPrice)
    ) {
      return (preClose - (data.maxPrice - preClose)).toFixed(2);
    } else {
      return data.minPrice;
    }
  };
  const priceRange = Math.max(
    Math.abs(data.maxPrice - preClose),
    Math.abs(preClose - data.minPrice)
  );
  const percentMax = Number(((priceRange / preClose) * 100).toFixed(2));
  const percentMin = -percentMax;

  return {
    textStyle: {
      fontFamily: "Microsoft YaHei, PingFang SC, sans-serif", // 优先使用雅黑，回退苹方/系统无衬线
    },
    grid: {
      top: 20,
      left: 5,
      right: 5,
      bottom: 0,
      containLabel: true,
      show: true,
      borderColor: "#eee",
    },
    title: {
      text: `均价：${data.currentAvgPrice}`,
      left: 6,
      top: 0,
      textStyle: {
        color: "#666",
        fontSize: 14,
        fontWeight: "normal",
      },
    },
    xAxis: {
      type: "value",
      min: 0,
      max: 240,
      axisLabel: {
        show: false,
      },
      splitLine: {
        show: false,
      },
      splitNumber: 3,
      boundaryGap: false,
      axisLine: {
        lineStyle: {
          color: "#eee",
        },
      },
      axisPointer: {
        label: {
          backgroundColor: "#fff",
          borderColor: "#eee",
          formatter: ({ value }) => {
            let totalMinutes;
            if (value <= 120) {
              totalMinutes = 570 + value;
            } else {
              totalMinutes = 780 + (value - 121);
            }
            const hours = Math.floor(totalMinutes / 60)
              .toString()
              .padStart(2, "0");
            const minutes = (totalMinutes % 60).toString().padStart(2, "0");
            return `${hours}:${minutes}`;
          },
        },
      },
    },
    yAxis: [
      {
        scale: true,
        splitLine: {
          show: false,
        },
        axisTick: {
          show: false,
        },
        axisLabel: {
          inside: true,
          color: "#999",
          formatter: (value) => value.toFixed(2),
          verticalAlign: "bottom",
          verticalAlignMaxLabel: "top",
          lineHeight: 20,
        },
        splitNumber: 1,

        max: function (value) {
          if (
            Math.abs(data.maxPrice - props.timeData.pre_close) >
            Math.abs(props.timeData.pre_close - data.minPrice)
          ) {
            return data.maxPrice;
          } else {
            return (
              props.timeData.pre_close +
              (props.timeData.pre_close - data.minPrice)
            ).toFixed(2);
          }
        },
        min: function (value) {
          if (
            Math.abs(data.maxPrice - props.timeData.pre_close) >
            Math.abs(props.timeData.pre_close - data.minPrice)
          ) {
            return (
              props.timeData.pre_close -
              (data.maxPrice - props.timeData.pre_close)
            ).toFixed(2);
          } else {
            return data.minPrice;
          }
        },
        axisLine: {
          lineStyle: {
            color: "#eee",
          },
        },
      },
      {
        scale: true,
        position: "right",
        axisTick: {
          show: false,
        },
        splitLine: { show: false },
        axisLabel: {
          inside: true,
          color: "#999",
          formatter: (value) => `${value.toFixed(2)}%`,
          verticalAlign: "bottom",
          verticalAlignMaxLabel: "top",
          lineHeight: 20,
        },
        splitNumber: 1,
        interval: percentMax * 2,
        max: function (value) {
          if (
            Math.abs(data.maxPrice - props.timeData.pre_close) >
            Math.abs(props.timeData.pre_close - data.minPrice)
          ) {
            return (
              (data.maxPrice - props.timeData.pre_close) /
              props.timeData.pre_close
            ).toFixed(2);
          } else {
            return (
              (props.timeData.pre_close - data.maxPrice) /
              props.timeData.pre_close
            ).toFixed(2);
          }
        },
        min: function (value) {
          if (
            Math.abs(data.maxPrice - props.timeData.pre_close) >
            Math.abs(props.timeData.pre_close - data.minPrice)
          ) {
            return (
              (
                (data.maxPrice - props.timeData.pre_close) /
                props.timeData.pre_close
              ).toFixed(2) * -1
            );
          } else {
            return (
              (
                (props.timeData.pre_close - data.maxPrice) /
                props.timeData.pre_close
              ).toFixed(2) * -1
            );
          }
        },
        axisLine: {
          lineStyle: {
            color: "#eee",
          },
        },
      },
    ],
    series: [
      {
        type: "line",
        data: data.prices,
        yAxisIndex: 0,
        z: 100,
        areaStyle: {
          color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
            { offset: 0, color: "rgba(83,114,222,0.6)" },
            { offset: 1, color: "rgba(83,114,222,.05)" },
          ]),
        },
        lineStyle: {
          width: 1,
          color: "#4e749b",
        },
        symbol: "none",
        markLine: {
          silent: true,
          symbol: "none",
          label: {
            show: true,
            position: "middle",
            formatter: "",
            color: "#999",
          },
          lineStyle: {
            color: "#eee",
            type: "solid",
            width: 1,
          },
          data: [
            { xAxis: 0 },
            { xAxis: 60 },
            { xAxis: 120 },
            { xAxis: 180 },
            { xAxis: 240 },
          ],
        },
      },
      {
        type: "line",
        z: 101,
        data: data.avgPrices,
        yAxisIndex: 0,
        smooth: true,
        lineStyle: {
          color: "#ca9547",
          width: 1,
        },
        symbol: "none",
      },
    ],
    animation: false,
  };
};

const getVolumeOption = (data) => ({
  textStyle: {
    fontFamily: "Microsoft YaHei, PingFang SC, sans-serif", // 优先使用雅黑，回退苹方/系统无衬线
  },
  title: {
    text: `现量：${data.currentVolume}万`,
    left: 6,
    top: 0,
    textStyle: {
      color: "#666",
      fontSize: 14,
      fontWeight: "normal",
    },
  },
  grid: {
    top: 20,
    left: 5,
    right: 5,
    bottom: 25,
    containLabel: false,
    borderColor: "#eee",
    borderWidth: 1,
  },
  xAxis: {
    type: "value",
    min: 0,
    max: 240,
    axisLabel: {
      show: false,
    },
    axisTick: {
      show: false,
    },
    splitLine: {
      show: false,
    },
    boundaryGap: false,
    axisLine: {
      lineStyle: {
        color: "#eee",
      },
    },
    axisPointer: {
      label: {
        backgroundColor: "#fff",
        borderColor: "#eee",
        formatter: ({ value }) => {
          let totalMinutes;
          if (value <= 120) {
            totalMinutes = 570 + value;
          } else {
            totalMinutes = 780 + (value - 121);
          }
          const hours = Math.floor(totalMinutes / 60)
            .toString()
            .padStart(2, "0");
          const minutes = (totalMinutes % 60).toString().padStart(2, "0");
          return `${hours}:${minutes}`;
        },
      },
    },
  },
  yAxis: {
    splitLine: {
      show: true,
      lineStyle: {
        type: "solid",
        color: "#eee",
      },
    },
    axisTick: {
      show: false,
    },
    axisLine: {
      show: true,
      lineStyle: {
        color: "#eee",
      },
    },
    scale: true,
    splitNumber: 1,
    min: 0,
    max: data.maxVolume,
    axisLabel: {
      inside: true,
      color: "#999",
      formatter: (value) => {
        return value > 0 ? `${(value / 10000).toFixed(1)}万` : "";
      },
      verticalAlign: "bottom",
      verticalAlignMaxLabel: "top",
      lineHeight: 20,
    },
  },

  graphic: [
    {
      type: "text",
      left: "5",
      bottom: "5",
      z: 100,
      style: {
        text: "9:30",
        fill: "#666",
        fontSize: 12,
      },
    },
    {
      type: "text",
      right: "5",
      bottom: "5",
      z: 100,
      style: {
        text: "15:00",
        fill: "#666",
        fontSize: 12,
      },
    },
    {
      type: "text",
      left: "center",
      bottom: "5",
      z: 100,
      style: {
        text: "11:30",
        fill: "#666",
        fontSize: 12,
        textAlign: "center",
      },
    },
  ],
  series: [
    {
      type: "bar",
      data: data.volumes.map((v) => ({
        value: [v.time, v.value],
        itemStyle: {
          color: v.price > v.avgPrice ? "#b95f6c" : "#00a674",
        },
      })),
      barMaxWidth: 20,
      barCategoryGap: "0%",
      markLine: {
        silent: true,
        symbol: "none",
        label: {
          show: true,
          position: "middle",
          formatter: "",
          color: "#999",
        },
        lineStyle: {
          color: "#eee",
          type: "solid",
          width: 1,
        },
        data: [{ xAxis: 60 }, { xAxis: 120 }, { xAxis: 180 }],
      },
    },
  ],
  animation: false,
});

const initCharts = () => {
  const initialData = processData();

  mainInstance = echarts.init(mainChart.value);
  volumeInstance = echarts.init(volumeChart.value);

  mainInstance.setOption(getMainOption(initialData));
  volumeInstance.setOption(getVolumeOption(initialData));

  mainInstance.on("dataZoom", (params) => {
    volumeInstance.dispatchAction({
      type: "dataZoom",
      startValue: params.batch[0].startValue,
      endValue: params.batch[0].endValue,
    });
  });

  dataTimer = setInterval(() => {
    if (currentIndex >= tradingData.length - 1) {
      clearInterval(dataTimer);
      return;
    }
    currentIndex++;
    const newData = processData();

    mainInstance.setOption({
      title: {
        text: `均价：${newData.currentAvgPrice}`, // 动态更新标题
      },
      yAxis: [
        {
          max: function (value) {
            if (
              Math.abs(newData.maxPrice - props.timeData.pre_close) >
              Math.abs(props.timeData.pre_close - newData.minPrice)
            ) {
              return newData.maxPrice;
            } else {
              return (
                props.timeData.pre_close +
                (props.timeData.pre_close - newData.minPrice)
              ).toFixed(2);
            }
          },
          min: function (value) {
            if (
              Math.abs(newData.maxPrice - props.timeData.pre_close) >
              Math.abs(props.timeData.pre_close - newData.minPrice)
            ) {
              return (
                props.timeData.pre_close -
                (newData.maxPrice - props.timeData.pre_close)
              ).toFixed(2);
            } else {
              return newData.minPrice;
            }
          },
        },
        {
          max: function (value) {
            if (
              Math.abs(newData.maxPrice - props.timeData.pre_close) >
              Math.abs(props.timeData.pre_close - newData.minPrice)
            ) {
              return (
                (newData.maxPrice - props.timeData.pre_close) /
                props.timeData.pre_close
              ).toFixed(2);
            } else {
              return (
                (props.timeData.pre_close - newData.maxPrice) /
                props.timeData.pre_close
              ).toFixed(2);
            }
          },
          min: function (value) {
            if (
              Math.abs(newData.maxPrice - props.timeData.pre_close) >
              Math.abs(props.timeData.pre_close - newData.minPrice)
            ) {
              return (
                (
                  (newData.maxPrice - props.timeData.pre_close) /
                  props.timeData.pre_close
                ).toFixed(2) * -1
              );
            } else {
              return (
                (
                  (props.timeData.pre_close - newData.maxPrice) /
                  props.timeData.pre_close
                ).toFixed(2) * -1
              );
            }
          },
        },
      ],
      series: [{ data: newData.prices }, { data: newData.avgPrices }],
    });

    volumeInstance.setOption({
      title: {
        text: `现量：${newData.currentVolume}万`, // 动态更新标题
      },
      series: [
        {
          data: newData.volumes.map((v) => ({
            value: [v.time, v.value],
            itemStyle: {
              color: v.price > v.avgPrice ? "#b95f6c" : "#00a674",
            },
          })),
        },
      ],
      yAxis: {
        max: newData.maxVolume,
        interval: newData.maxVolume * 2,
      },
    });
  }, 300);
};

const handleResize = () => {
  mainInstance?.resize();
  volumeInstance?.resize();
};

onMounted(() => {
  initCharts();
  window.addEventListener("resize", handleResize);
});

onBeforeUnmount(() => {
  window.removeEventListener("resize", handleResize);
  mainInstance?.dispose();
  volumeInstance?.dispose();
  clearInterval(dataTimer);
});
</script>

<style scoped>
.chart-container {
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

.main-chart {
  flex: 2;
  height: 66.66%;
}

.volume-chart {
  flex: 1;
  height: 33.33%;
}
</style>